#include <string.h> // memset()、bzero()
// #include <functional>
// #include <atomic>
// #include <strings.h>

#include "./TcpServer.h"
#include "./utility/Logger.h" // 单独组件，用户/开发者自行引入
// #include "./reactor/TcpConnection.h"

// loop是开发者传入的，需要避免为空
// TODO: 还是会继续loop为空逻辑，优化loop为空的处理
static EventLoop *CheckLoopNotNull(EventLoop *loop)
{
    if (!loop)
    {
        LOG_FATAL("%s:%s:%d mainLoop is null!\n", __FILE__, __FUNCTION__, __LINE__);
    }
    return loop;
}

// OPTIMIZE: new -> std::make_unique<>
TcpServer::TcpServer(EventLoop *loop,
                     const InetAddress &listenAddr,
                     ListenOption listenOpt,
                     const std::string &threadName)
    : loop_(CheckLoopNotNull(loop)),
      ipPort_(listenAddr.toIpPort()),
      // ListenOption转换为传递默认布尔值
      acceptor_(std::make_unique<Acceptor>(loop, listenAddr, listenOpt == ListenOption::ReusePort)),
      threadName_(threadName),
      threadPool_(std::make_unique<EventLoopThreadPool>(loop, this->threadName_))
// connectionCallback_(),
// readWriteCallback_(),
// nextConnId_(1),
// isStart_(0)
{
    // 有新连接：Acceptor::handleRead()回调1 -> TcpServer::newConnection()回调2
    // placeholders：实际newConnection(参数1, 参数2)传进来
    this->acceptor_->setNewConnCallback(
        std::bind(&TcpServer::newConnection, this, std::placeholders::_1, std::placeholders::_2));
}

TcpServer::~TcpServer()
{
    for (auto &item : this->conns_)
    {
        // 局部shared_ptr<>，出右括号自动释放对象
        TcpConnectionPtr conn(item.second); // 新的
        item.second.reset();                // 旧的置空

        // 销毁连接
        // 注意：在其所在的线程loop执行
        conn->getLoop()->runCallback(std::bind(&TcpConnection::connectDestroyed, conn));
    }
}

void TcpServer::setThreadNum(int threadNum)
{
    // int numThreads_ = numThreads;
    this->threadNum_ = threadNum;
    this->threadPool_->setThreadNum(this->threadNum_);
}

void TcpServer::setThreadInitCallback(const ThreadInitCallback &cb)
{
    this->threadInitCallback_ = cb;
}

void TcpServer::setConnectionCallback(const ConnectionCallback &cb)
{
    this->connectionCallback_ = cb;
}

void TcpServer::setReadWriteCallback(const ReadWriteCallback &cb)
{
    this->readWriteCallback_ = cb;
}

void TcpServer::setWriteCompleteCallback(const WriteCompleteCallback &cb)
{
    this->writeCompleteCallback_ = cb;
}

// 新连接：Acceptor::handleRead()回调1 -> TcpServer::newConnection()回调2
void TcpServer::newConnection(int sockFd, const InetAddress &peerAddr)
{
    // 日志
    char buf[64]{0};
    snprintf(buf, sizeof(buf), "-%s#%d", this->ipPort_.c_str(), this->connId_);
    ++this->connId_; // 没有使用原子类型，因为只在mainloop执行，线程安全
    std::string connName = this->threadName_ + buf;

    LOG_INFO("TcpServer::newConnection [%s] - new connection [%s] from %s\n",
             this->threadName_.c_str(), connName.c_str(), peerAddr.toIpPort().c_str());

    // 获取本机地址信息
    sockaddr_in localAddr{};
    socklen_t localAddrLen = sizeof(localAddr);
    ::bzero(&localAddr, localAddrLen);
    if (::getsockname(sockFd, (sockaddr *)&localAddr, &localAddrLen) < 0)
    {
        LOG_ERROR("sockets::getLocalAddr");
    }

    // 选择一个subLoop处理connfd->conn channel
    // 轮询
    // EventLoop *ioLoop = threadPool_->getNextLoop(peerAddr.toIp()); // 一致性哈希算法选择
    EventLoop *subLoop = this->threadPool_->getNextLoop();
    InetAddress localAddr2(localAddr);

    // 封装TcpConnection
    // OPTIMIZE: new -> make_shared<>
    TcpConnectionPtr conn(std::make_shared<TcpConnection>(subLoop,
                                                          connName,
                                                          sockFd,
                                                          localAddr2,
                                                          peerAddr));
    this->conns_[connName] = conn;
    // Channel绑定TcpConnection的handle读写关闭错误 回调1
    // 用户->TcpServer->TcpConnection的 回调2
    // 回调1 会调用 回调2
    conn->setConnectionCallback(this->connectionCallback_);
    conn->setReadWriteCallback(this->readWriteCallback_);
    conn->setWriteCompleteCallback(this->writeCompleteCallback_);
    conn->setCloseCallback(std::bind(&TcpServer::removeConnection, this, std::placeholders::_1));

    // 直接调用建立连接，放到所在线程建立连接
    subLoop->runCallback(std::bind(&TcpConnection::connectEstablished, conn));
}

void TcpServer::removeConnection(const TcpConnectionPtr &conn)
{
    this->loop_->runCallback(std::bind(&TcpServer::removeConnectionInLoop, this, conn));
}

void TcpServer::removeConnectionInLoop(const TcpConnectionPtr &conn)
{
    LOG_INFO("TcpServer::removeConnectionInLoop [%s] - connection %s\n",
             this->threadName_.c_str(), conn->getName().c_str());

    this->conns_.erase(conn->getName());

    // 连接肯定不在主线程，用queueInLoop()，而不是runCallback()判断再queueInLoop()
    EventLoop *subLoop = conn->getLoop();
    subLoop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
}

void TcpServer::start()
{
    // 防止一个TcpServer对象被start多次
    // if (started_++ == 0)
    // if (this->isStart_.fetch_add(1) == 0)
    bool expected = false;
    if (this->isStart_.compare_exchange_strong(expected, true)) // 期待false就置为true返回true，否则返回false
    {
        this->threadPool_->start(this->threadInitCallback_);
        // acceptor在主线程中，用原始指针
        this->loop_->runCallback(std::bind(&Acceptor::listen, this->acceptor_.get()));
    }
}